"use strict";

// mobitytut.library
var mbtlib = (function() {
    var m = {
        clone: function(obj) {
            var obj2 = {};
            $.extend(true, obj2, obj);
            return obj2;
        },
        error: function(obj) {
            var obj2 = m.clone(obj);

            // Add toString() for console log
            obj2.toString = function() {
                return JSON.stringify(obj2);
            }
            return obj2;
        },
        split_words: function(text) {
            var words = text.split(/[ \n\r\t]+/);

            if (words.length > 0 && !words[0]) {
                words.splice(0, 1);
            }
            if (words.length > 0 && !words[words.length - 1]) {
                words.splice(words.length - 1, 1);
            }
            return words;
        },
        random_int: function(min, max) {
            return Math.floor(Math.random() * (max - min)) + min;
        }
    };
    return m;
})();

// mobitytut.navigation
var mbtnav = (function() {
    var m = {
        new_nav: function() {
            return {
                view_by_name: {}
            };
        },
        add_view: function(nav, name, view) {
            nav.view_by_name[name] = view;
        },
        show_view: function(nav, name, args, push_state) {
            var view = nav.view_by_name[name];

            if (!view) {
                throw mbtlib.error({view_not_found:{name:name}});
            }
            if (push_state) {
                if (history) {
                    var state = {
                        mbtnav_vstate : {
                            name: name,
                            args: args
                        }
                    }
                    // console.log("pushState", JSON.stringify(state));
                    history.pushState(state, null, location);
                }
            }
            view(args);
        },
        is_view_state: function(state) {
            return !!(state && state.mbtnav_vstate);
        },
        restore_view_state: function(state, nav) {
            var vstate = state.mbtnav_vstate;
            m.show_view(nav, vstate.name, vstate.args, false);
        }
    };
    return m;
})();

// mobitytut.template
var mbttmpl = (function() {
    var m = {
        new_tmpl: function(name) {
            return $("#template .tmpl_" + name).clone();
        },
        display_tmpl: function(template) {
            var $display = $("#display");
            $display.children().remove();
            $display.append(template);
        },
        copy_content: function(to, from) {
            $(to).contents().replaceWith($(from).clone().contents());
        }
    };
    return m;
})();

// mobitytut.word_generator
var mbtwgen = (function() {
    var m = {
        SEQ: "SEQ",
        RAND: "RAND",
        ITER: "ITER",

        new_seq: function(words) {
            if (words.length == 0) {
                throw mbtlib.error({invalid_arg:"words.length == 0"})
            }
            return {
                type: m.SEQ,
                words: words,
                seq_index: 0
            };
        },
        new_rand: function(words) {
            if (words.length == 0) {
                throw mbtlib.error({invalid_arg:"words.length == 0"});
            }
            return {
                type: m.RAND,
                words: words
            };
        },
        new_iter: function(min_count, max_count, wgen) {
            if (min_count < 1 || max_count < min_count) {
                throw mbtlib.error({invalid_arg:"min_count < 1 || max_count < min_count"});
            }
            if (!wgen) {
                throw mbtlib.error({invalid_arg:"!wgen"});
            }
            return {
                type: m.ITER,
                iter_min: min_count,
                iter_max: max_count,
                iter_wgen: wgen
            };
        },
        gen_word: function(wgen) {
            if (wgen.type === m.ITER) {
                var count = mbtlib.random_int(wgen.iter_min, wgen.iter_max + 1);
                var word = "";

                for (var i = 0; i < count; i++) {
                    word += m.gen_word(wgen.iter_wgen)
                }
                return word;
            }
            if (wgen.type === m.SEQ) {
                if (wgen.seq_index >= wgen.words.length) {
                    wgen.seq_index = 0;
                }
                return wgen.words[wgen.seq_index++];
            }
            if (wgen.type  === m.RAND) {
                var i = mbtlib.random_int(1, wgen.words.length);
                var w = wgen.words[i];

                if (w === undefined) {
                    throw mbtlib.error({undefined_word:"wgen.words[i] is undefined"});
                }
                return w
            }
            throw mbtlib.error({invalid_wgen:"wgen is not setup properly"});
        }
    };
    return m;
})();

// mobitytut.typing
var mbttyp = (function() {
    var m = {
        RETURN: "\u23ce",
        new_tmpl: function(conf) {
            var $tmpl = mbttmpl.new_tmpl("typing");
            var $words = $(".words", $tmpl);
            var $input = $("textarea", $tmpl);

            function add_word() {
                var word = mbtwgen.gen_word(conf.wgen);
                $words.append($("<span></span>").text(word));
                $words.append(document.createTextNode("\n"));
                $words.children().first().addClass("first");
            }

            function get_set(name, value) {
                if (value === undefined) {
                    return $tmpl.data(name)
                }
                $tmpl.data(name, value)
            }

            function right_count(count) {
                return get_set("right_count", count)
            }

            function wrong_count(count) {
                return get_set("wrong_count", count)
            }

            function word_input(word, event) {
                var $first_word = $words.children().first();
                var first_word = $first_word.text();

                if (first_word === word) {
                    $first_word.remove();
                    add_word();
                    $input.val("");
                    event.preventDefault();
                    right_count(right_count() + 1);
                } else {
                    $first_word.addClass("wrong");
                    wrong_count(wrong_count() + 1);
                    // console.log(first_word, "!=", word);
                }
                update_status();
            }

            function update_status() {
                var right = right_count();
                var wrong = wrong_count();
                var total = right + wrong;
                var $status = $(".status", $tmpl);

                if (total > 0) {
                    var right_percent = Math.round(right / total * 100);
                    var $health = $(".health", $status);
                    $health.css("width", right_percent + "%");
                    $status.show();
                } else {
                    $status.hide();
                }
                // console.log(right, "/", wrong, "=", right_percent, "%");
            }

            update_status();
            $words.children().remove();

            var word_count = 4;

            for (var i = 0; i < word_count; ++i) {
                add_word();
            }

            right_count(0);
            wrong_count(0);
            $input.unbind("keypress");
            $input.keydown(function(event) {
                var kc_space = 32;
                var kc_enter = 13;

                if (event.keyCode === kc_space) {
                    word_input($input.val(), event);
                } else if (event.keyCode === kc_enter) {
                    word_input($input.val() + m.RETURN, event);
                } else {
                    // console.log(event);
                }
            });

            $input.attr("autofocus", "autofocus");
            return $tmpl;
        }
    };
    return m;
})();

// mobitytut.main
var mbtmain = (function() {
    var m = {
        init: function() {
            var nav = m.get_nav();

            for (var i in m) {
                if (i.indexOf("v_") == 0) {
                    mbtnav.add_view(nav, i, m[i]);
                }
            }
            if (window.history) {
                window.addEventListener("popstate", function(event) {
                    // console.log("popstate", JSON.stringify(event.state));

                    if (mbtnav.is_view_state(event.state)) {
                        mbtnav.restore_view_state(event.state, nav);
                    } else {
                        mbtnav.show_view(nav, "v_stages", undefined, true);
                    }
                });
            }
            m.v_stages();
        },
        get_nav: function() {
            var $doc = $(document);
            var nav = $doc.data("nav");

            if (!nav) {
                var nav = mbtnav.new_nav();
                $doc.data("nav", nav);
            }
            return nav;
        },
        v_stages: function() {
            var $tmpl = mbttmpl.new_tmpl("stages");
            var nav = m.get_nav();

            $("li", $tmpl).each(function(i) {
                var $li = $(this);

                $li.click(function() {
                    mbtnav.show_view(nav, "v_stage_" + i, undefined, true);
                });
            });
            mbttmpl.display_tmpl($tmpl);
        },
        display_stage: function(index, $tmpl) {
            var $desc = $(".tmpl_stage_" + index + "_desc");

            mbttmpl.copy_content($(".title", $tmpl), $(".tmpl_stages li")[index]);

            if ($desc.length > 0) {
                mbttmpl.copy_content($(".desc", $tmpl), $desc);
            }
            mbttmpl.display_tmpl($tmpl);
        },
        v_stage_0: function() {
            var words = mbtlib.split_words($(".tmpl_four_noble_truths").text());
            var wgen = mbtwgen.new_seq(words);
            var $tmpl = mbttyp.new_tmpl({wgen:wgen});
            m.display_stage(0, $tmpl);
        },
        v_stage_1: function() {
            var chars = ["g", "h", "q", "p"];
            var wgen = mbtwgen.new_rand(chars);
            var $tmpl = mbttyp.new_tmpl({wgen:wgen});
            m.display_stage(1, $tmpl);
        },
        v_stage_2: function() {
            var chars = ["g", "h", "q", "p"];
            var wgen = mbtwgen.new_iter(1, 3, mbtwgen.new_rand(chars));
            var $tmpl = mbttyp.new_tmpl({wgen:wgen});
            m.display_stage(1, $tmpl);
        },
        v_stage_3: function() {
            var conf = mbttyp.new_conf();
            m.display_stage(3, conf);
        },
        v_stage_4: function() {
            var conf = mbttyp.new_conf();
            m.display_stage(4, conf);
        }
    }
    return m;
})();

$(function() {
    mbtmain.init(document);
});
